/// ****************************************************************************
/// Author:	        Robin Zhu
/// Create Date:	2012-2-13
/// Purpose: 		记录集合抽象类定义文件
/// ****************************************************************************
/// Modify By		Date			Remark
/// Robin           2012-3-28       增加Any函数的新实现，用于判断是否有满足某个条件的记录
/// Robin           2012-6-6        增加多个函数用于覆盖扩展方法的实现
/// Robin           2012-12-29      去掉对IQueryable的继承，使之成为一个独立的类
/// Robin           2013-2-22       讲First，Single的参数类型变为Expression<Func<TItem, bool>>，以便将条件生成为SQL
/// ****************************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RB.DataAccess;
using System.Linq.Expressions;
using RB.DataAccess.Linq;

namespace RB.Domain.RelationalMapping
{
    /// <summary>
    /// 记录集合抽象类，用于将一个领域模型对象映射到一个关系数据表
    /// </summary>
    /// <typeparam name="TItem">领域模型对象类型</typeparam>
    public class RecordSet<TItem>
        where TItem : class
    {
        public RecordSet()
        {
        }

        public RecordSet(bool isReadOnly)
        {
            _isReadOnly = isReadOnly;
        }

        /// <summary>
        /// 提供一个可以使用Executor初始化的版本，以便使所有的查询均使用指定的Executor执行
        /// </summary>
        /// <param name="exec"></param>
        public RecordSet(Executor exec)
        {
            _queryable = exec.Query<TItem>();
        }

        /// ****************************************************************************
        #region 自定义方法

        public virtual void Add(TItem item, Executor exec)
        {
            if (IsReadOnly)
                throw new NotSupportedException("The collection is read-only");

            exec.Insert<TItem>(item);
        }

        public void Add(TItem item)
        {
            if (IsReadOnly)
                throw new NotSupportedException("The collection is read-only");

            using (Executor exec = DataContext.CreateExecutor())
            {
                Add(item, exec);
            }
        }

        public virtual int RemoveAll(Expression<Func<TItem, bool>> match, Executor exec)
        {
            if (IsReadOnly)
                throw new NotSupportedException("The collection is read-only");

            if (match == null)
                throw new ArgumentNullException("match");
          
            return exec.Delete<TItem>(match);
        }

        public int RemoveAll(Expression<Func<TItem, bool>> match)
        {
            if (IsReadOnly)
                throw new NotSupportedException("The collection is read-only");

            using (Executor exec = DataContext.CreateExecutor())
            {
                return RemoveAll(match, exec);
            }
        }

        public virtual int Update<TField>(Expression<Func<TItem, TField>> fields, Expression<Func<TItem, bool>> match, Executor exec)
        {
            if (IsReadOnly)
                throw new NotSupportedException("The collection is read-only");

            return exec.Update(fields, match);
        }

        public int Update<TField>(Expression<Func<TItem, TField>> fields, Expression<Func<TItem, bool>> match)
        {
            if (IsReadOnly)
                throw new NotSupportedException("The collection is read-only");

            using (Executor exec = DataContext.CreateExecutor())
            {
                return Update<TField>(fields, match, exec);
            }
        }

        private bool _isReadOnly;
        /// <summary>
        /// 是否只读
        /// </summary>
        public bool IsReadOnly
        {
            get
            {
                return _isReadOnly;
            }
        }

        #endregion 自定义方法

        /// ****************************************************************************
        #region 实现ICollection<T>接口

        public IEnumerator<TItem> GetEnumerator()
        {
            return this.AsQueryable().GetEnumerator();
        }


        public Type ElementType
        {
            get { return typeof(TItem); }
        }

        public Expression Expression
        {
            get { return this.AsQueryable().Expression; }
        }

        public IQueryProvider Provider
        {
            get { return this.AsQueryable().Provider; }
        }

        #endregion 实现ICollection<T>接口

        /// ****************************************************************************
        #region 覆盖IEnumerable的扩展方法

        public virtual List<TItem> ToList()
        {
            return this.AsQueryable().ToList();
        }

        public IEnumerable<TItem> AsEnumerable()
        {
            return this.AsQueryable().AsEnumerable();
        }

        private SqlQueryable<TItem> _queryable = null;

        public virtual IQueryable<TItem> AsQueryable()
        {
            return AsQueryable(DataContext.CreateExecutor());
        }

        public IQueryable<TItem> AsQueryable(Executor exec)
        {

            if (_queryable == null)
            {
                _queryable = exec.Query<TItem>();
            }

            return _queryable;
        }

        /// <summary>
        /// 确定序列中是否有任何元素满足条件
        /// </summary>
        /// <param name="predicate">用于测试元素是否满足条件的函数</param>
        /// <returns>如果源序列中有任何元素通过指定谓词中的测试，则为 true；否则为 false</returns>
        public virtual bool Any(Expression<Func<TItem, bool>> predicate)
        {
            var q = this.AsQueryable();
            q = q.Where(predicate);
            return q.Count() > 0;
        }

        /// <summary>
        /// 返回序列中满足条件的第一个元素；如果未找到这样的元素，则返回默认值。
        /// </summary>
        /// <returns>如果 source 为空，则返回 default( TSource)；否则返回 source 中的第一个元素。</returns>
        public virtual TItem FirstOrDefault()
        {
            return this.AsQueryable().FirstOrDefault();
        }

        /// <summary>
        /// 返回序列中满足指定条件的第一个元素，如果未找到这样的元素，则返回默认值。
        /// </summary>
        /// <param name="predicate">用于测试每个元素是否满足条件的函数。</param>
        /// <returns>如果 source 为空或没有元素通过 predicate 指定的测试，则返回 default( TSource)，否则返回 source 中通过 predicate 指定的测试的第一个元素。</returns>
        public virtual TItem FirstOrDefault(Expression<Func<TItem, bool>> predicate)
        {
            return this.AsQueryable().Where(predicate).FirstOrDefault();
        }

        /// <summary>
        /// 返回序列中满足条件的第一个元素。
        /// </summary>
        /// <returns>如果 source 为空，则返回 default( TSource)；否则返回 source 中的第一个元素。</returns>
        public virtual TItem First()
        {
            return this.AsQueryable().First();
        }

        /// <summary>
        /// 返回序列中满足指定条件的第一个元素。
        /// </summary>
        /// <param name="predicate">用于测试每个元素是否满足条件的函数。</param>
        /// <returns>如果 source 为空或没有元素通过 predicate 指定的测试，则返回 default( TSource)，否则返回 source 中通过 predicate 指定的测试的第一个元素。</returns>
        public virtual TItem First(Expression<Func<TItem, bool>> predicate)
        {
            return this.Where(predicate).First();
        }

        /// <summary>
        /// 返回序列中满足指定条件的唯一元素；如果这类元素不存在，则返回默认值；如果有多个元素满足该条件，此方法将引发异常。
        /// </summary>
        /// <param name="predicate">用于测试元素是否满足条件的函数。</param>
        /// <returns>如果未找到这样的元素，则返回输入序列中满足条件的单个元素或 default ( TSource)。 </returns>
        public virtual TItem SingleOrDefault(Expression<Func<TItem, bool>> predicate)
        {
            return this.Where(predicate).SingleOrDefault();
        }

        /// <summary>
        /// 返回序列中满足指定条件的唯一元素；如果这类元素不存在，则返回默认值；如果有多个元素满足该条件，此方法将引发异常。
        /// </summary>
        /// <param name="predicate">用于测试元素是否满足条件的函数。</param>
        /// <returns>满足 predicate 中条件的输入序列中的单个元素。 </returns>
        public virtual TItem Single(Expression<Func<TItem, bool>> predicate)
        {
            return this.Where(predicate).Single();
        }

        /// <summary>
        /// 基于谓词筛选值序列。
        /// </summary>
        /// <param name="predicate">用于测试每个元素是否满足条件的函数。</param>
        /// <returns>一个 IQueryable<T>，包含满足由 predicate 指定的条件的输入序列中的元素。 </returns>
        public virtual IQueryable<TItem> Where(Expression<Func<TItem, bool>> predicate)
        {
            return this.AsQueryable().Where(predicate);
        }


        #endregion 覆盖IEnumerable的扩展方法
    }
}
